`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    02:54:43 09/21/2013 
// Design Name: 
// Module Name:    PS2KeyboardController 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module PS2KeyboardController(input  clk,
	 input reset,
	 input enable,
	 input [3:0] address,
    input [31:0] dataIn,
	 output [31:0] dataOut,
	 input write,
	 output done,
	 output interrupt,
	 input clk_50,
	 inout PS2_CLK,
	 inout PS2_DATA
    );
	 
	 assign done = 1;
	
	 
	 parameter DRP_ID = 32'hA001004A;
	 
	 
	 wire [7:0] command = 8'b0;
	 wire sendCommand = 1'b0;
	 
	 wire commandSent;
	 wire error_timed_out;
	 
	 wire [7:0] received_data;
	 wire received_data_ready;
	 
	 PS2_Controller ps2Instance(clk_50, reset, command, sendCommand, PS2_CLK, PS2_DATA, commandSent, error_timed_out, received_data, received_data_ready);
	 
	 reg lastReadyValue;
	 always @(posedge clk) lastReadyValue <= received_data_ready;
	 
	 wire readyEdge = ~lastReadyValue & received_data_ready; //& (received_data != 8'hFE) ; //detects the ready wire going from low to high
	 
	 //building of scan code squence 
	 
	 wire dataReady;
	 reg [1:0] sp;
	 reg [23:0] scanCode;
	 reg justSet;
	 always @(posedge clk) begin
		if(reset) {sp, scanCode, justSet} <= {2'b0, 24'b0, 1'b0};
		else if(readyEdge ) {sp, scanCode, justSet} <=  (dataReady | scanCode[7:0] == 8'h0) ? {2'b0, {16'b0, received_data}, 1'b1} : {{sp[0], 1'b1}, {scanCode[15:0], received_data}, 1'b1};
		else {sp, scanCode, justSet} <= {sp, scanCode, 1'b0};
	 end
	 
	 assign dataReady = ~((scanCode[7:0] == 8'hE0) | (scanCode[7:0] == 8'hF0) | (scanCode[7:0] == 8'hE1) | (scanCode[7:0] == 8'h0) | ((scanCode[7:0] == 8'h14) & scanCode[15:8] == 8'hE1));
	 
	 //buffer
	 
	 reg lastBuilderReady;
	 always @(posedge clk) lastBuilderReady <= dataReady & justSet;
	 
	 reg [25:0] buffer;
	 reg newData;
	 always @(posedge clk) begin
		if(reset) {newData, buffer} <= {1'b0, 26'b0};
		else if(~lastBuilderReady & dataReady & justSet) {newData, buffer} <= {1'b1, {sp, scanCode}};
		else if(address == 1 & ~write & enable) {newData, buffer} <= {1'b0, buffer};
		else {newData, buffer} <= {newData, buffer};
	 end
	 assign interrupt = 1'b0; //newData;
	 wire isCommand = (~buffer[25] & ~buffer[24]) & ((buffer[7:0] == 8'hFA) | (buffer[7:0] == 8'hAA) | (buffer[7:0] == 8'hEE) | (buffer[7:0] == 8'hFE) | (buffer[7:0] == 8'h00) | (buffer[7:0] == 8'hFF));
	 reg moreToCome;
	 always @ (posedge clk) begin
		case(buffer[23:0])
		24'h00E012: moreToCome <= 1;
		24'hE11477: moreToCome <= 1;
		24'hE1F014: moreToCome <= 1;
		24'hE0F07C: moreToCome <= 1;
		default: moreToCome <= 0;
		endcase
	 end
	 reg [31:0] dataOutReg;
	 always @ (*) begin
		case(address)
		4'h0: dataOutReg <= {31'b0, newData};
		4'h1: dataOutReg <= {4'b0, isCommand, moreToCome, buffer};
		4'hF: dataOutReg <= DRP_ID;
		default: dataOutReg <= 32'b0;
		endcase
	 end
	 assign dataOut = dataOutReg;


endmodule
